package com.gylang.print.richtext;

import ch.qos.logback.core.util.CloseUtil;
import cn.hutool.core.collection.CollUtil;
import com.gylang.print.richtext.append.IRichAppend;
import com.gylang.print.richtext.pdf.RichPdfRender;
import com.gylang.print.richtext.processor.*;
import com.gylang.print.richtext.resolver.StyleResolver;
import com.gylang.print.richtext.component.*;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author gylang
 * data 2021/7/10
 */
public class RichHelper {

	private static final List<IRichAppend> APPEND_POOL = new ArrayList<>();
	private static final List<StyleResolver> STYLE_RESOLVER_POOL = new ArrayList<>();
	private static final Map<Class<?>, RichPdfRender<?>> RICH_PDF_RENDER_POOL = new HashMap<>();

	static {
		TableProcessor tableProcessor = new TableProcessor();
		TextProcessor textProcessor = new TextProcessor();
		ListProcessor listProcessor = new ListProcessor();
		BrProcessor brProcessor = new BrProcessor();
		HrProcessor hrProcessor = new HrProcessor();
		ImageProcessor imageProcessor = new ImageProcessor();

		APPEND_POOL.add(tableProcessor);
		APPEND_POOL.add(textProcessor);
		APPEND_POOL.add(listProcessor);

		STYLE_RESOLVER_POOL.add(tableProcessor);
		STYLE_RESOLVER_POOL.add(listProcessor);
		STYLE_RESOLVER_POOL.add(imageProcessor);
		STYLE_RESOLVER_POOL.add(brProcessor);
		STYLE_RESOLVER_POOL.add(hrProcessor);


		STYLE_RESOLVER_POOL.add(textProcessor);

		RICH_PDF_RENDER_POOL.put(BaseRichBr.class, brProcessor);
		RICH_PDF_RENDER_POOL.put(BaseRichHr.class, hrProcessor);
		RICH_PDF_RENDER_POOL.put(BaseRichText.class, textProcessor);
		RICH_PDF_RENDER_POOL.put(BaseRichImage.class, imageProcessor);
	}

	/**
	 * 富文本html展位替换
	 *
	 * @param origin 原html
	 * @param data   业务数据
	 * @return 替换后的html
	 */
	public static Element append(Element origin, Map<String, Object> data) {

		appendRecursion(origin, data);
		return origin;
	}

	/**
	 * 富文本html转pdf
	 *
	 * @param component html解析出来的节点数据
	 * @param richBox   容器
	 * @return pdf
	 */
	public static PDDocument toPdf(List<BaseRich> component, RichBox richBox) {

		PDDocument pdDocument = new PDDocument();
		richBox.setDocument(pdDocument);
		PDPage page = new PDPage(new PDRectangle(richBox.getWidth(), richBox.getHeight()));
		pdDocument.addPage(page);
		richBox.setPage(page);
		Coords coords = Coords.of(0, richBox.getHeight() - richBox.getMarginT());
		for (BaseRich baseRich : component) {
			RichPdfRender<?> richPdfRender = RICH_PDF_RENDER_POOL.get(baseRich.getClass());
			if (null != richPdfRender) {
				coords = ((RichPdfRender<BaseRich>) richPdfRender).render(coords, richBox, baseRich);
			}
		}
		CloseUtil.closeQuietly(richBox.getContentStream());
		return pdDocument;
	}

	/**
	 * 富文本html转pdf
	 *
	 * @param baseRich html解析出来的节点数据
	 * @param coords    坐标
	 * @param richBox   容器
	 * @return pdf
	 */
	public static void renderPdf(BaseRich baseRich, Coords coords, RichBox richBox) {
		RichPdfRender<?> richPdfRender = RICH_PDF_RENDER_POOL.get(baseRich.getClass());
		if (null != richPdfRender) {
			((RichPdfRender<BaseRich>) richPdfRender).render(coords, richBox, baseRich);
		}
	}


	/**
	 * 富文本html样式解析
	 *
	 * @param origin 当前html节点
	 * @param parent 父节点样式
	 * @return 富文本html
	 */
	public static List<BaseRich> style(Element origin, BaseRich parent) {
		List<BaseRich> component = new ArrayList<>();
		style(origin, component, parent);
		return component;
	}

	/**
	 * 富文本html样式解析
	 *
	 * @param origin 当前html节点
	 * @return 富文本html
	 */
	public static List<BaseRich> style(Element origin) {
		List<BaseRich> component = new ArrayList<>();
		style(origin, component, null);
		return component;
	}

	/**
	 * 富文本html样式解析
	 *
	 * @param origin    当前html节点
	 * @param parent    父节点样式
	 * @param component 节点列表
	 * @return 富文本html
	 */
	public static void style(Element origin, List<BaseRich> component, BaseRich parent) {

		boolean resolveSuccess = false;
		for (StyleResolver styleResolver : STYLE_RESOLVER_POOL) {
			boolean resolve = styleResolver.resolve(origin, component, parent);
			if (resolve) {
				resolveSuccess = true;
				break;
			}
		}

		Elements children = origin.children();
		if (CollUtil.isEmpty(children)) {
			return;
		}
		for (Element child : children) {
			if (!resolveSuccess) {
				style(child, component, parent);
			}

		}
	}

	/**
	 * 富文本html展位替换递归遍历
	 *
	 * @param document 原html
	 * @param map      业务数据
	 * @return 替换后的html
	 */
	private static void appendRecursion(Element document, Map<String, Object> map) {

		Elements children = document.children();
		if (CollUtil.isEmpty(children)) {
			return;
		}
		for (Element child : children) {
			for (IRichAppend iRichAppend : APPEND_POOL) {
				iRichAppend.append(child, map);
			}

			appendRecursion(child, map);
		}
	}
}
